﻿using Microsoft.AspNetCore.SignalR;
using OA.Infrastructure.DomainModels.Message;
using OA.Infrastructure.DomainModels.TemporaryAuthorization;
using OA.Infrastructure.SignalR.Abstractions;
using OA.Infrastructure.SignalR.Hubs;
using OA.Infrastructure.WeCom.Generator;
using Quartz;
using System.Collections.Concurrent;

namespace OA.Infrastructure.Impl;

public class TemporaryAuthorizationToolChains<TModel>
    where TModel : TemporaryAuthorizationBase, new()
{
    private readonly DbContext _context;
    private readonly ISignalRService _signalRService;
    private readonly IWeComService _weComService;
    private readonly ISchedulerFactory _schedulerFactory;

    private readonly string _method = null!;
    private readonly string _callbackMethod = null!;

    private readonly ConcurrentDictionary<string, TModel> _localRequest;

    public TemporaryAuthorizationToolChains(
        DbContext context,
        ISignalRService signalRService,
        IWeComService weComService,
        ISchedulerFactory schedulerFactory,
        ConcurrentDictionary<string, TModel> request,
        string method,
        string callbackMethod)
    {
        _context = context;
        _signalRService = signalRService;
        _weComService = weComService;
        _schedulerFactory = schedulerFactory;
        _localRequest = request;
        _method = method;
        _callbackMethod = callbackMethod;
    }

    public WeComButtonTemplateCardEngine DefaultTemplateCardEngine(User @operator)
    {
        var engine = TemplateCardGenerateEngineFactory.GetButtonTemplateCardEngine(true, false);

        var from = @operator.UserId == "admin" ? "系统管理员" : $"$userName={@operator.UserId}$";
        if (@operator.UserId == "admin")
        {
            engine.AddHoriztontalContentItemForText("申请人", @operator.Name);
        }
        else
        {
            engine.AddHoriztontalContentItemForUserDetail("申请人", @operator.Name, @operator.UserId);
        }

        return engine
                    .WithSource(new TemplateCardSource
                    {
                        Desc = "OA-资产管理系统",
                        Desc_color = 0
                    })
                    .WithTitle("临时授权请求", $"来自{from}的临时授权请求");
    }

    public async Task SendCardToWeComAsync(WeComButtonTemplateCard card, string? key = null)
    {
#if DEBUG
        var result = await _weComService.SendButtonInteractionMessageAsync("8163", card, key);
#elif RELEASE
                var admins = await _context.Set<User>()
                    .Include(x => x.Roles)
                    .Include(x => x.Department).ThenInclude(x => x.Roles)
                    .Select(x => new { x.UserId, x.Roles, DepartmentRoles = x.Department.Roles })
                    .Where(x => x.UserId != "admin")
                    .Where(x => x.Roles.Any(n => App.AdminRoleCodes.Any(m => m == n.RoleCode)) ||
                        x.DepartmentRoles.Any(n => App.AdminRoleCodes.Any(m => m == n.RoleCode)))
                    .Select(x => x.UserId)
                    .AsNoTracking()
                    .ToListAsync(cancellationToken);

                admins.Add("8163");

                var result = await _weComService.SendButtonInteractionMessageAsync(string.Join('|', admins), card, key);
#endif
        if (!result.EnsureSucceed())
        {
            throw new Exception("请求失败");
        }
    }

    public async Task SendToApproverAsync(TemporaryAuthorizationRecord record, CancellationToken cancellationToken)
    {
        foreach (var role in App.AdminRoleCodes)
        {
            await _signalRService.Factory
                .CreateGenericFactory<NotifyHub>()
                .CreateGroupProxy(role)
                .SendAsync(_method, new MessageRecord<TemporaryAuthorizationRecord>
                {
                    Sender = "System",
                    Data = record
                }, cancellationToken);
        }
    }

    public async Task SendToCommitterAsync(string account, TemporaryAuthorizationCallbackRecord record, CancellationToken cancellationToken)
    {
        await _signalRService.Factory
                .CreateGenericFactory<NotifyHub>()
                .CreateUserProxy(account)
                .SendAsync(_callbackMethod, new MessageRecord<TemporaryAuthorizationCallbackRecord>
                {
                    Sender = "System",
                    Data = record
                }, cancellationToken);
    }

    public async Task GrantAsync(TModel model, TemporaryAuthorizationCallbackRecord callbackRecord, CancellationToken cancellationToken)
    {
        await SendAggregationMessageCoreAsync(model, callbackRecord, false, cancellationToken);
    }

    public async Task RejectAsync(string key, TModel model, TemporaryAuthorizationCallbackRecord callbackRecord, CancellationToken cancellationToken)
    {
        await SendAggregationMessageCoreAsync(model, callbackRecord, true, cancellationToken);

        _localRequest.TryRemove(key, out _);
    }

    public async Task ScheduleJob<TJob>(string identity, JobDataMap map, DateTimeOffset triggerDate, string? description, CancellationToken cancellationToken = default)
        where TJob : IJob
    {
        var sched = await _schedulerFactory.GetScheduler(cancellationToken);

        var job = JobBuilder.Create<TJob>()
            .WithDescription(description ?? "临时授权接续任务")
            .WithIdentity(identity)
            .UsingJobData(map)
            .Build();

        var trigger = TriggerBuilder.Create()
            .WithIdentity($"{identity}-trigger")
            .StartAt(triggerDate)
        .Build();

        await sched.ScheduleJob(job, trigger, cancellationToken);
    }

    public async Task<bool> CanSendMessage(CancellationToken cancellationToken = default)
    {
        var systemSetting = await _context.Set<SystemSettings>()
                 .AsNoTracking()
                 .FirstOrDefaultAsync(cancellationToken);

        systemSetting ??= new();

        return systemSetting.SendMessage;
    }

    public bool TryAdd(string key, TModel model)
    {
        return _localRequest.TryAdd(key, model);
    }

    public bool TryExtractRequest(string key, out TModel model)
    {
        if (_localRequest.TryGetValue(key, out var localModel))
        {
            model = localModel;

            return true;
        }

        model = new();

        return false;
    }

    public bool TryRemove(string key, out TModel model)
    {
        if (_localRequest.TryRemove(key, out var localModel))
        {
            model = localModel;

            return true;
        }

        model = new();
        return false;
    }

    public ConcurrentDictionary<string, TModel> Package()
        => _localRequest;

    private async Task SendAggregationMessageCoreAsync(TModel model, TemporaryAuthorizationCallbackRecord callbackRecord, bool rejected, CancellationToken cancellationToken)
    {
        var record = new TemporaryAuthorizationRecord
        {
            Commiter = model.Commiter.Name,
            Description = rejected ? "已被处理，状态：驳回" : "已被处理，状态：授权"
        };

        if (App.ManagedByDocker)
        {
            await _weComService.SendTextMessageAsync(model.Commiter.UserId, callbackRecord.Description);
        }

        await SendToCommitterAsync(model.Commiter.Account, callbackRecord, cancellationToken);

        await SendToApproverAsync(record, cancellationToken);
    }
}